#include "common.hpp"
#include "en.hpp"
#include <math.h>
#include <float.h>
#include <iostream>

using namespace std;


void remove_bad_jobs(std::vector<std::shared_ptr<job>>& jobs)
{
    for(int i=0; i<jobs.size(); i++)
    {
        int tpskip = 0;
        if(jobs[i]->b!=NULL)
        {
            tpskip = jobs[i]->b->pskip;
            jobs[i]->b->pskip = 0;
            pair<int, int> p = jobs[i]->b->find_nearest_free_space();
            jobs[i]->b->pskip = tpskip;

            if(p.first == -1 || p.second == -1)
            {
                auto it = jobs.begin();
                advance(it, i);
                jobs.erase(it);
            }
        }
        if(jobs[i]->x >= 0 && jobs[i]->x < en::w && jobs[i]->y >= 0 && jobs[i]->y < en::h)
        {
            if(en::collision_win[jobs[i]->x][jobs[i]->y] == NON_PATHABLE && jobs[i]->b==NULL)
            {
                auto it = jobs.begin();
                advance(it, i);
                jobs.erase(it);
            }
        }
    }
}

void assign_jobs_peons(std::vector<std::shared_ptr<job>>& jobs, std::vector<peon*>& available)
{
    int jnum = 0;

    std::vector<std::shared_ptr<job>> valid_jobs;
    valid_jobs.reserve(jobs.size());

    ///when there are free jobs but no who arent hungry, itll do jobs*hungrypeons

    while(jobs.size()!=0 && jnum < jobs.size())
    {
        auto j = jobs[jnum];

        int id_min = -1;
        float distance_min = FLT_MAX;

        int n = 0;
        for(auto& i : available)
        {
            float xd = i->x - j->x;
            float yd = i->y - j->y;
            float distance = (xd*xd + yd*yd);

            if(distance < distance_min && i->should_accept(j))
            {
                id_min = n;
                distance_min = distance;
            }

            n++;
        }

        if(id_min!=-1)
        {
            auto it = available.begin();
            advance(it, id_min);

            peon* p = available[id_min];

            p->job_assigned = true;

            p->task = j;

            j->p = p;

            available.erase(it);

            jnum++;
        }
        else
        {
            jnum++;

            valid_jobs.push_back(j);
        }
    }

    //jobs = valid_jobs;

    jobs.assign(valid_jobs.begin(), valid_jobs.end());

    for(auto& i : jobs)
    {
        if(i->peon_trait_id==-1)
            i->priority += 1.0f;
    }
}


void en::assign_jobs()
{
    std::vector<peon*> available;
    std::vector<std::vector<peon*>> catagories;

    for(auto& i : peon::trait_list)
        catagories.push_back({});

    for(auto& i : peons)
    {
        if(i->job_assigned)
            continue;

        if(!i->needy)
        {
            available.push_back(i);
        }
        if(i->needy)
        {
            for(int j=0; j<i->needs.size(); j++)
            {
                if(i->needs[j]) ///need to pick most urgent need, or available need somehow and do that
                {
                    catagories[j].push_back(i);
                    break;
                }
            }
        }
    }

    ///remove bad jobs
    remove_bad_jobs(jobs);
    for(auto& i : en::satisfying_peon_jobs)
        remove_bad_jobs(i);


    ///need to have retry counter for jobs, remove if theyve been done too many times.
    ///somehow suppress job creation from objects?

    std::sort(jobs.begin(), jobs.end(), o_more);
    for(auto& i : en::satisfying_peon_jobs)
        std::sort(i.begin(), i.end(), o_more);

    assign_jobs_peons(jobs, available);
    for(int i=0; i<catagories.size(); i++)
        assign_jobs_peons(en::satisfying_peon_jobs[i], catagories[i]);
}
